home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / programer2 / icon / Source / Icont / C / Tlex < prev    next >
Encoding:
Text File  |  1990-07-20  |  19.4 KB  |  779 lines

  1. /*
  2.  * tlex.c -- the lexical analyzer.
  3.  */
  4.  
  5. #include "../h/config.h"
  6. #include "general.h"
  7. #include "tproto.h"
  8. #include "trans.h"
  9. #include "token.h"
  10. #include "tlex.h"
  11. #include "tree.h"
  12. #include <ctype.h>
  13.  
  14. #if MACINTOSH
  15. #if MPW
  16. #include <CursorCtl.h>
  17. #define CURSORINTERVAL 100
  18. #endif                    /* MPW */
  19. #endif                    /* MACINTOSH */
  20.  
  21. /*
  22.  * Prototypes.
  23.  */
  24.  
  25. hidden    int        ctlesc        Params((noargs));
  26. hidden    struct toktab   *findres    Params((noargs));
  27. hidden    struct toktab   *getident    Params((int ac,int *cc));
  28. hidden    struct toktab   *getnum        Params((int ac,int *cc));
  29. hidden    struct toktab   *getopr        Params((int ac,int *cc));
  30. hidden    struct toktab   *getstring    Params((int ac,int *cc));
  31. hidden    int        hexesc        Params((noargs));
  32. hidden    int        nextchar    Params((noargs));
  33. hidden    int        octesc        Params((int ac));
  34. hidden    int        setfilenm    Params((int c));
  35. hidden    int        setlineno    Params((noargs));
  36.  
  37. #define isletter(s)    (isupper(c) | islower(c))
  38.  
  39. #if EBCDIC
  40. extern char ToEBCDIC[256], FromEBCDIC[256];
  41. #endif                    /* EBCDIC */
  42.  
  43. #if !EBCDIC
  44. #define tonum(c)        (isdigit(c) ? (c - '0') : ((c & 037) + 9))
  45.  
  46. /*
  47.  * esctab - translates single-character escapes in string literals.
  48.  */
  49.  
  50. static char esctab[] = {
  51.    000,   001,   002,   003,   004,   005,   006,   007,   /* NUL-BEL */
  52.    010,   011,   012,   013,   014,   015,   016,   017,   /* BS -SI */
  53.    020,   021,   022,   023,   024,   025,   026,   027,   /* DLE-ETB */
  54.    030,   031,   032,   033,   034,   035,   036,   037,   /* CAN-US */
  55.    ' ',   '!',   '"',   '#',   '$',   '%',   '&',   '\'',  /* !"#$%&' */
  56.    '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',   /* ()*+,-./ */
  57.    000,   001,   002,   003,   004,   005,   006,   007,   /* 01234567 */
  58.    010,   011,   ':',   ';',   '<',   '=',   '>',   '?',   /* 89:;<=>? */
  59.    '@',   'A',   '\b',  'C',   0177,  033,   014,   'G',   /* @ABCDEFG */
  60.    'H',   'I',   'J',   'K',   '\n',  'M',  '\n',   'O',   /* HIJKLMNO */
  61.    'P',   'Q',   '\r',  'S',   '\t',  'U',   013,   'W',   /* PQRSTUVW */
  62.    'X',   'Y',   'Z',   '[',   '\\',  ']',   '^',   '_',   /* XYZ[\]^_ */
  63.    '`',   'a',   '\b',  'c',   0177,  033,   014,   'g',   /* `abcdefg */
  64.    'h',   'i',   'j',   'k',   '\n',  'm',   '\n',  'o',   /* hijklmno */
  65.    'p',   'q',   '\r',  's',   '\t',  'u',   013,   'w',   /* pqrstuvw */
  66.    'x',   'y',   'z',   '{',   '|',   '}',   '~',   0177,  /* xyz{|}~ */
  67.    0200,  0201,  0202,  0203,  0204,  0205,  0206,  0207,
  68.    0210,  0211,  0212,  0213,  0214,  0215,  0216,  0217,
  69.    0220,  0221,  0222,  0223,  0224,  0225,  0226,  0227,
  70.    0230,  0231,  0232,  0233,  0234,  0235,  0236,  0237,
  71.    0240,  0241,  0242,  0243,  0244,  0245,  0246,  0247,
  72.    0250,  0251,  0252,  0253,  0254,  0255,  0256,  0257,
  73.    0260,  0261,  0262,  0263,  0264,  0265,  0266,  0267,
  74.    0270,  0271,  0272,  0273,  0274,  0275,  0276,  0277,
  75.    0300,  0301,  0302,  0303,  0304,  0305,  0306,  0307,
  76.    0310,  0311,  0312,  0313,  0314,  0315,  0316,  0317,
  77.    0320,  0321,  0322,  0323,  0324,  0325,  0326,  0327,
  78.    0330,  0331,  0332,  0333,  0334,  0335,  0336,  0337,
  79.    0340,  0341,  0342,  0343,  0344,  0345,  0346,  0347,
  80.    0350,  0351,  0352,  0353,  0354,  0355,  0356,  0357,
  81.    0360,  0361,  0362,  0363,  0364,  0365,  0366,  0367,
  82.    0370,  0371,  0372,  0373,  0374,  0375,  0376,  0377,
  83.   };
  84. #else                                   /* !EBCDIC */
  85. /*
  86.  *  This is the EBCDIC table for handling escapes.
  87.  */
  88. static char esctab[] = {
  89.    0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,
  90.    0x08,  0x09,  0x0a,  0x0b,  0x0c,  0x0d,  0x0e,  0x0f,
  91.    0x10,  0x11,  0x12,  0x13,  0x14,  0x15,  0x16,  0x17,
  92.    0x18,  0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,
  93.    0x20,  0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,
  94.    0x28,  0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,
  95.    0x30,  0x31,  0x32,  0x33,  0x34,  0x35,  0x36,  0x37,
  96.    0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,
  97.    ' ',   0x41,  0x42,  0x43,  0x44,  0x45,  0x46,  0x47,
  98.    0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d,  0x4e,  0x4f,
  99.    0x50,  0x51,  0x52,  0x53,  0x54,  0x55,  0x56,  0x57,
  100.    0x58,  0x59,  0x5a,  0x5b,  0x5c,  0x5d,  0x5e,  0x5f,
  101.    0x60,  0x61,  0x62,  0x63,  0x64,  0x65,  0x66,  0x67,
  102.    0x68,  0x69,  0x6a,  0x6b,  0x6c,  0x6d,  0x6e,  0x6f,
  103.    0x70,  0x71,  0x72,  0x73,  0x74,  0x75,  0x76,  0x77,
  104.    0x78,  0x79,  0x7a,  0x7b,  0x7c,  0x7d,  0x7e,  0x7f,
  105.    0x80,  'a',   0x16,  'c',   0x07,  0x27,  0x0c,  'g',
  106.    'h',   'i',   0x8a,  0x8b,  0x8c,  0x8d,  0x8e,  0x8f,
  107.  
  108. #if EBCDIC == 2
  109.    0x90,  'j',   'k',   0x15,  'm',   0x15,  'o',   'p',
  110. #else                    /* EBCDIC == 2 */
  111.    0x90,  'j',   'k',   0x25,  'm',   0x15,  'o',   'p',
  112. #endif                    /* EBCDIC == 2 */
  113.  
  114.    'q',   0x0d,  0x9a,  0x9b,  0x9c,  0x9d,  0x9e,  0x9f,
  115.    0xa0,  0xa1,  's',   0x05,  'u',   0x0b,  'w',   'x',
  116.    'y',   'z',   0xaa,  0xab,  0xac,  0xad,  0xae,  0xaf,
  117.    0xb0,  0xb1,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
  118.    0xb8,  0xb9,  0xba,  0xbb,  0xbc,  0xbd,  0xbe,  0xbf,
  119.    0xc0,  'A',   0x16,  'C',   0x07,  0x27,  0x0c,  'G',
  120.    'H',   'I',   0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
  121.  
  122. #if EBCDIC == 2
  123.    0xd0,  'J',   'K',   0x15,  'M',   0x15,  'O',   'P',
  124. #else                    /* EBCDIC == 2 */
  125.    0xd0,  'J',   'K',   0x25,  'M',   0x15,  'O',   'P',
  126. #endif                    /* EBCDIC == 2 */
  127.  
  128.    'Q',   0x0d,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
  129.    0xe0,  0xe1,  'S',   0x05,  'U',   0x0b,  'W',   'X',
  130.    'Y',   'Z',   0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
  131.    0,   1,   2,   3,     4,     5,     6,     7,
  132.    8,   9,   0xfa,   0xfb,  0xfc,  0xfd,  0xfe,  0xff,
  133.    };
  134. #endif                    /* !EBCDIC */
  135.  
  136. struct node tok_loc =
  137.    {0, NULL, 0, 0};    /* "model" node containing location of current token */
  138.  
  139. /*
  140.  * yylex - find the next token in the input stream, and return its token
  141.  *  type and value to the parser.
  142.  *
  143.  * Variables of interest:
  144.  *
  145.  *  cc - character following last token.
  146.  *  comflag - set if in a comment.
  147.  *  nlflag - set if a newline was between the last token and the current token
  148.  *  lastend - set if the last token was an Ender.
  149.  *  lastval - when a semicolon is inserted and returned, lastval gets the
  150.  *   token value that would have been returned if the semicolon hadn't
  151.  *   been inserted.
  152.  */
  153.  
  154. static struct toktab *lasttok = NULL;
  155. static int lastend = 0;
  156. static int eofflag = 0;
  157. static int cc = '\n';
  158.  
  159. int yylex()
  160.    {
  161.    register struct toktab *t;
  162.    register int c;
  163.    int nlflag;
  164.    int comflag;
  165.    static nodeptr lastval;
  166.    static struct node semi_loc;
  167.  
  168.    if (lasttok != NULL) {
  169.       /*
  170.        * A semicolon was inserted and returned on the last call to yylex,
  171.        *  instead of going to the input, return lasttok and set the
  172.        *  appropriate variables.
  173.        */
  174.  
  175.       yylval = lastval;
  176.       tok_loc = *lastval;
  177.       t = lasttok;
  178.       goto ret;
  179.       }
  180.    nlflag = 0;
  181.    comflag = 0;
  182. loop:
  183.    c = cc;
  184.    /*
  185.     * Remember where a semicolon will go if we insert one.
  186.     */
  187.    semi_loc.n_file = tok_loc.n_file;
  188.    semi_loc.n_line = in_line;
  189.    semi_loc.n_col = incol;
  190.    /*
  191.     * Skip whitespace and comments and process #line directives.
  192.     */
  193.    while (c == Comment || isspace(c)) {
  194.       if (c == '\n') {
  195.          nlflag++;
  196.          c = NextChar;
  197.      if (c == Comment) {
  198.             /*
  199.          * Check for #line directive at start of line.
  200.              */
  201.             if (('l' == (c = NextChar)) &&
  202.                 ('i' == (c = NextChar)) &&
  203.                 ('n' == (c = NextChar)) &&
  204.                 ('e' == (c = NextChar))) {
  205.                c = setlineno();
  206.            while ((c == ' ') || (c == '\t'))
  207.           c = NextChar;
  208.                if (c != EOF && c != '\n')
  209.                   c = setfilenm(c);
  210.            }
  211.         while (c != EOF && c != '\n')
  212.                c = NextChar;
  213.         }
  214.          }
  215.       else {
  216.      if (c == Comment) {
  217.         while (c != EOF && c != '\n')
  218.                c = NextChar;
  219.         }
  220.          else {
  221.             c = NextChar;
  222.             }
  223.          }
  224.       }
  225.    /*
  226.     * A token is the next thing in the input.  Set token location to
  227.     *  the current line and column.
  228.     */
  229.    tok_loc.n_line = in_line;
  230.    tok_loc.n_col = incol;
  231.  
  232.    if (c == EOF) {
  233.       /*
  234.        * End of file has been reached.    Set eofflag, return T_Eof, and
  235.        *  set cc to EOF so that any subsequent scans also return T_Eof.
  236.        */
  237.       if (eofflag++) {
  238.      eofflag = 0;
  239.      cc = '\n';
  240.      yylval = NULL;
  241.      return 0;
  242.      }
  243.       cc = EOF;
  244.       t = T_Eof;
  245.       yylval = NULL;
  246.       goto ret;
  247.       }
  248.  
  249.    /*
  250.     * Look at current input character to determine what class of token
  251.     *  is next and take the appropriate action.  Note that the various
  252.     *  token gathering routines write a value into cc.
  253.     */
  254.    if (isalpha(c) || (c == '_')) {   /* gather ident or reserved word */
  255.       if ((t = getident(c, &cc)) == NULL)
  256.      goto loop;
  257.       }
  258.    else if (isdigit(c)) {        /* gather numeric literal */
  259.       if ((t = getnum(c, &cc)) == NULL)
  260.      goto loop;
  261.       }
  262.    else if (c == '"' || c == '\'') {    /* gather string or cset literal */
  263.       if ((t = getstring(c, &cc)) == NULL)
  264.      goto loop;
  265.       }
  266.    else {            /* gather longest legal operator */
  267.       if ((t = getopr(c, &cc)) == NULL)
  268.      goto loop;
  269.       yylval = OpNode(t->t_type);
  270.       }
  271.    if (nlflag && lastend && (t->t_flags & Beginner)) {
  272.       /*
  273.        * A newline was encountered between the current token and the last,
  274.        *  the last token was an Ender, and the current token is a Beginner.
  275.        *  Return a semicolon and save the current token in lastval.
  276.        */
  277.       lastval = yylval;
  278.       lasttok = t;
  279.       tok_loc = semi_loc;
  280.       yylval = OpNode(SEMICOL);
  281.       return SEMICOL;
  282.       }
  283. ret:
  284.    /*
  285.     * Clear lasttok, set lastend if the token being returned is an
  286.     *  Ender, and return the token.
  287.     */
  288.    lasttok = 0;
  289.    lastend = t->t_flags & Ender;
  290.    return (t->t_type);
  291.    }
  292.  
  293. #ifdef MultipleRuns
  294. /*
  295.  * yylexinit - initialize variables for multiple runs
  296.  */
  297. novalue yylexinit()
  298.    {
  299.    lasttok = NULL;
  300.    lastend = 0;
  301.    eofflag = 0;
  302.    cc = '\n';
  303.    }
  304.  
  305. #endif                    /* MultipleRuns */
  306. /*
  307.  * getident - gather an identifier beginning with ac.  The character
  308.  *  following identifier goes in cc.
  309.  */
  310.  
  311. static struct toktab *getident(ac, cc)
  312. int ac;
  313. int *cc;
  314.    {
  315.    register int c;
  316.    register char *p;
  317.    register struct toktab *t;
  318.  
  319.    c = ac;
  320.    p = strf;
  321.    /*
  322.     * Copy characters into string space until a non-alphanumeric character
  323.     *  is found.
  324.     */
  325.    do {
  326.       if (p >= stre)
  327.      tsyserr("out of string space");
  328.       *p++ = c;
  329.       c = NextChar;
  330.       } while (isalnum(c) || (c == '_'));
  331.    if (p >= stre)
  332.       tsyserr("out of string space");
  333.    *p++ = 0;
  334.    *cc = c;
  335.    /*
  336.     * If the identifier is a reserved word, make a ResNode for it and return
  337.     *  the token value.  Otherwise, install it with putid, make an
  338.     *  IdNode for it, and return.
  339.     */
  340.    if ((t = findres()) != NULL) {
  341.       yylval = ResNode(t->t_type);
  342.       return t;
  343.       }
  344.    else {
  345.       yylval = IdNode(putid((int)(p-strf)));
  346.       return (struct toktab *)T_Ident;
  347.       }
  348.    }
  349.  
  350. /*
  351.  * findres - if the string just copied into the string space by getident
  352.  *  is a reserved word, return a pointer to its entry in the token table.
  353.  *  Return NULL if the string isn't a reserved word.
  354.  */
  355.  
  356. static struct toktab *findres()
  357.    {
  358.    register struct toktab *t;
  359.    register char c, *p;
  360.  
  361.    p = strf;
  362.    c = *p;
  363.    if (!islower(c))
  364.       return NULL;
  365.    /*
  366.     * Point t at first reserved word that starts with c (if any).
  367.     */
  368.    if ((t = restab[c - 'a']) == NULL)
  369.       return NULL;
  370.    /*
  371.     * Search through reserved words, stopping when a match is found
  372.     *  or when the current reserved word doesn't start with c.
  373.     */
  374.    while (t->t_word[0] == c) {
  375.       if (strcmp(t->t_word, p) == 0)
  376.      return t;
  377.       t++;
  378.       }
  379.    return NULL;
  380.    }
  381.  
  382. /*
  383.  * getnum - gather a numeric literal starting with ac and put the
  384.  *  character following the literal into *cc.
  385.  */
  386.  
  387. static struct toktab *getnum(ac, cc)
  388. int ac;
  389. int *cc;
  390.    {
  391.    register int c, r, state;
  392.    char *p;
  393.    int realflag;
  394.  
  395.    c = ac;
  396.    r = tonum(c);
  397.    p = strf;
  398.    state = 0;
  399.    realflag = 0;
  400.    for (;;) {
  401.       if (p >= stre)
  402.      tsyserr("out of string space");
  403.       *p++ = c;
  404.       c = NextChar;
  405.       switch (state) {
  406.      case 0:        /* integer part */
  407.         if (isdigit(c))        { r = r * 10 + tonum(c); continue; }
  408.         if (c == '.')           { state = 1; realflag++; continue; }
  409.         if (c == 'e' || c == 'E')  { state = 2; realflag++; continue; }
  410.         if (c == 'r' || c == 'R')  {
  411.            state = 5;
  412.            if (r < 2 || r > 36)
  413.           tfatal("invalid radix for integer literal", (char *)NULL);
  414.            continue;
  415.            }
  416.         break;
  417.      case 1:        /* fractional part */
  418.         if (isdigit(c))   continue;
  419.         if (c == 'e' || c == 'E')   { state = 2; continue; }
  420.         break;
  421.      case 2:        /* optional exponent sign */
  422.         if (c == '+' || c == '-') { state = 3; continue; }
  423.      case 3:        /* first digit after e, e+, or e- */
  424.         if (isdigit(c)) { state = 4; continue; }
  425.         tfatal("invalid real literal", (char *)NULL);
  426.         break;
  427.      case 4:        /* remaining digits after e */
  428.         if (isdigit(c))   continue;
  429.         break;
  430.      case 5:        /* first digit after r */
  431.         if ((isdigit(c) || isletter(c)) && tonum(c) < r)
  432.            { state = 6; continue; }
  433.         tfatal("invalid integer literal", (char *)NULL);
  434.         break;
  435.      case 6:        /* remaining digits after r */
  436.         if (isdigit(c) || isletter(c)) {
  437.            if (tonum(c) >= r) {    /* illegal digit for radix r */
  438.           tfatal("invalid digit in integer literal", (char *)NULL);
  439.           r = tonum('z');       /* prevent more messages */
  440.           }
  441.            continue;
  442.            }
  443.         break;
  444.      }
  445.       break;
  446.       }
  447.    if (p >= stre)
  448.       tsyserr("out of string space");
  449.    *p++ = 0;
  450.    *cc = c;
  451.    if (realflag) {
  452.       yylval = RealNode(putid((int)(p-strf)));
  453.       return T_Real;
  454.       }
  455.    yylval = IntNode(putid((int)(p-strf)));
  456.    return T_Int;
  457.    }
  458.  
  459. /*
  460.  * getstring - gather a string literal starting with ac and place the
  461.  *  character following the literal in *cc.
  462.  */
  463.  
  464. static struct toktab *getstring(ac, cc)
  465. int ac;
  466. int *cc;
  467.    {
  468.    register int c, sc;
  469.    register char *p;
  470.    char *lc;
  471.    int len;
  472.  
  473.    sc = c = ac;
  474.    p = strf;
  475.    lc = 0;
  476.    while ((c = NextChar) != sc && c != '\n' && c != EOF) {
  477.    contin:
  478.       if (c == '_')
  479.      lc = p;
  480.       else if (!isspace(c))
  481.      lc = 0;
  482.       if (c == Escape) {
  483.      c = NextChar;
  484.  
  485. #ifdef VarTran
  486.      *p++ = Escape;
  487. #else                    /* VarTran */
  488.      if (isoctal(c))
  489.         c = octesc(c);
  490.      else if (c == 'x')
  491.         c = hexesc();
  492.      else if (c == '^')
  493.         c = ctlesc();
  494.      else
  495.         c = esctab[c];
  496. #endif                    /* VarTran */
  497.  
  498.      if (c == EOF)
  499.         goto noquote;
  500.      }
  501.       if (p >= stre)
  502.      tsyserr("out of string space");
  503.       *p++ = c;
  504.       }
  505.    if (p >= stre)
  506.       tsyserr("out of string space");
  507.    *p++ = 0;
  508.    if (c == sc)
  509.       *cc = ' ';
  510.    else {
  511.       if (c == '\n' && lc) {
  512.      p = lc;
  513.      while ((c = NextChar) != EOF && isspace(c)) ;
  514.      if (c != EOF)
  515.         goto contin;
  516.      }
  517. noquote:
  518.       tfatal("unclosed quote", (char *)NULL);
  519.       *cc = c;
  520.       }
  521.    if (ac == '"') {     /* a string literal */
  522.       len = p - strf;
  523.       yylval = StrNode(putid((int)len), len);
  524.       return T_String;
  525.       }
  526.    else {        /* a cset literal */
  527.       len = p - strf;
  528.       yylval = CsetNode(putid((int)len), len);
  529.       return T_Cset;
  530.       }
  531.    }
  532.  
  533. #ifndef VarTran
  534.  
  535. /*
  536.  * ctlesc - translate a control escape -- backslash followed by
  537.  *  caret and one character.
  538.  */
  539.  
  540. static int ctlesc()
  541.    {
  542.    register int c;
  543.  
  544.    c = NextChar;
  545.    if (c == EOF)
  546.       return EOF;
  547.  
  548. #if !EBCDIC
  549.    return (c & 037);
  550. #else                    /* !EBCDIC */
  551.    return ToEBCDIC[FromEBCDIC[c] & 037];
  552.                         /* ctrl-x in EBCDIC is the EBCDIC equivalent */
  553.                         /* to ASCII ctrl-x                           */
  554. #endif                    /* !EBCDIC */
  555.  
  556.    }
  557.  
  558. /*
  559.  * octesc - translate an octal escape -- backslash followed by
  560.  *  one, two, or three octal digits.
  561.  */
  562.  
  563. static int octesc(ac)
  564. int ac;
  565.    {
  566.    register int c, nc, i;
  567.  
  568.    c = 0;
  569.    nc = ac;
  570.    i = 1;
  571.    do {
  572.       c = (c << 3) | (nc - '0');
  573.       nc = NextChar;
  574.       if (nc == EOF)
  575.      return EOF;
  576.       } while (isoctal(nc) && i++ < 3);
  577.    PushChar(nc);
  578.  
  579. #if EBCDIC != 2
  580.    return (c & 0377);
  581. #else                    /* EBCDIC != 2 */
  582.    return ToEBCDIC[c & 0377];
  583. #endif                    /* EBCDIC != 2 */
  584.    }
  585.  
  586. /*
  587.  * hexesc - translate a hexadecimal escape -- backslash-x
  588.  *  followed by one or two hexadecimal digits.
  589.  */
  590.  
  591. static int hexesc()
  592.    {
  593.    register int c, nc, i;
  594.  
  595.    c = 0;
  596.    i = 0;
  597.    while (i++ < 2) {
  598.       nc = NextChar;
  599.       if (nc == EOF)
  600.      return EOF;
  601.       if (nc >= 'a' && nc <= 'f')
  602.      nc -= 'a' - 10;
  603.       else if (nc >= 'A' && nc <= 'F')
  604.      nc -= 'A' - 10;
  605.       else if (isdigit(nc))
  606.      nc -= '0';
  607.       else {
  608.      PushChar(nc);
  609.      break;
  610.      }
  611.       c = (c << 4) | nc;
  612.       }
  613.  
  614. #if EBCDIC != 2
  615.    return c;
  616. #else                    /* EBCDIC != 2 */
  617.    return ToEBCDIC[c];
  618. #endif                    /* EBCDIC != 2 */
  619.  
  620.    }
  621.  
  622. #endif                    /* VarTran */
  623.  
  624. /*
  625.  * getopr - find the longest legal operator and return a pointer
  626.  *  to its entry in the token table.
  627.  */
  628.  
  629. static struct toktab *getopr(ac, cc)
  630. int ac;
  631. int *cc;
  632.    {
  633.    register struct optab *state;
  634.    register char c, i;
  635.  
  636.    state = state0;
  637.    c = ac;
  638.    for (;;) {
  639.       while ((i = state->o_input) && c != i)
  640.      state++;
  641.       switch (state->o_action) {
  642.      case A_Goto:
  643.         state = (struct optab *) state->o_val;
  644.         c = NextChar;
  645.         continue;
  646.      case A_Error:
  647.         tfatal("invalid character", (char *)NULL);
  648.         *cc = ' ';
  649.         return NULL;
  650.      case A_Return:
  651.         *cc = c;
  652.         return (struct toktab *)(state->o_val);
  653.      case A_Immret:
  654.         *cc = ' ';
  655.         return (struct toktab *)(state->o_val);
  656.      }
  657.       }
  658.    }
  659.  
  660. /*
  661.  * setlineno - set line number from #line comment, return following char.
  662.  */
  663.  
  664. static int setlineno()
  665.    {
  666.    register int c;
  667.  
  668.    while ((c = NextChar) == ' ' || c == '\t')
  669.       ;
  670.    if (c < '0' || c > '9') {
  671.       tfatal("no line number in #line directive", "");
  672.       while (c != EOF && c != '\n')
  673.      c = NextChar;
  674.       return c;
  675.       }
  676.    in_line = 0;
  677.    while (c >= '0' && c <= '9') {
  678.       in_line = in_line * 10 + (c - '0');
  679.       c = NextChar;
  680.       }
  681.    return c;
  682.    }
  683.  
  684. /*
  685.  * setfilenm -    set file name from #line comment, return following char.
  686.  *
  687.  * Assigning to comfile here does not provide the fine-grained
  688.  * control over filenames required by a real macro processor.
  689.  * setloc() in tcode.c ought to be restored to its earlier form and
  690.  * the initialization of filenames fixed.
  691.  */
  692.  
  693. static int setfilenm(c)
  694. register int c;
  695.    {
  696.    extern char *comfile;
  697.    register char *p;
  698.  
  699.    while (c == ' ' || c == '\t')
  700.       c = NextChar;
  701.    if (c != '"') {
  702.       tfatal("'\"' missing from file name in #line directive", "");
  703.       while (c != EOF && c != '\n')
  704.      c = NextChar;
  705.       return c;
  706.       }
  707.    p = strf;
  708.    while ((c = NextChar) != '"' && c != EOF && c != '\n') {
  709.       if (p >= stre)
  710.      tsyserr("out of string space");
  711.       *p++ = c;
  712.       }
  713.    *p++ = '\0';
  714.    if (c == '"') {
  715.       tok_loc.n_file = putid((int)(p-strf));
  716.       return NextChar;
  717.       }
  718.    else {
  719.       tfatal("'\"' missing from file name in #line directive", "");
  720.       return c;
  721.       }
  722.    }
  723.  
  724. /*
  725.  * nextchar - return the next character in the input.
  726.  */
  727.  
  728. static int nextchar()
  729.    {
  730.    register int c;
  731.  
  732. #if MACINTOSH
  733. #if MPW
  734.    {
  735.    static short cursorcount = CURSORINTERVAL;
  736.    if (--cursorcount == 0) {
  737.       RotateCursor(0);
  738.       cursorcount = CURSORINTERVAL;
  739.       }
  740.    }
  741. #endif                    /* MPW */
  742. #endif                    /* MACINTOSH */
  743.  
  744.    if (c = peekc) {
  745.       peekc = 0;
  746.       return c;
  747.       }
  748.    c = getc(srcfile);
  749.    switch (c) {
  750.       case EOF:
  751.      if (incol) {
  752.         c = '\n';
  753.         in_line++;
  754.         incol = 0;
  755.         peekc = EOF;
  756.         break;
  757.         }
  758.      else {
  759.         in_line = 0;
  760.         incol = 0;
  761.         break;
  762.         }
  763.       case '\n':
  764.      in_line++;
  765.      incol = 0;
  766.      break;
  767.       case '\t':
  768.      incol = (incol | 7) + 1;
  769.      break;
  770.       case '\b':
  771.      if (incol)
  772.         incol--;
  773.      break;
  774.       default:
  775.      incol++;
  776.       }
  777.    return c;
  778.    }
  779.